package com.goldman.aplt.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class RSAUtil {

    private static final String PUBLIC_KEY = "publicKey";
    private static final String PRIVATE_KEY = "privateKey";
    public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";

    /**
     * 生成公、私钥
     * 根据需要返回String或byte[]类型
     *
     * @return
     */
    public static Map<String, String> createRSAKeys() {
        Map<String, String> keyPairMap = new HashMap<>();
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
            keyPairGenerator.initialize(2048, new SecureRandom());
            KeyPair keyPair = keyPairGenerator.generateKeyPair();

            PublicKey publicKey = keyPair.getPublic();
            PrivateKey privateKey = keyPair.getPrivate();
            //获取公、私钥值
            String publicKeyValue = byte2Base64String(publicKey.getEncoded());
            String privateKeyValue = byte2Base64String(privateKey.getEncoded());
            //存入
            keyPairMap.put(PUBLIC_KEY, publicKeyValue);
            keyPairMap.put(PRIVATE_KEY, privateKeyValue);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return keyPairMap;
    }

//    public static void main(String[] args) {
////        System.out.println(JsonUtil.toJsonStr(Security.getProviders()));
////        ProviderList var2 = Providers.getProviderList();
////        Security.addProvider(new BouncyCastleProvider());
//        Map<String, String> a = createRSAKeys();
//        System.out.println("publicKey:" +a.get("publicKey"));
//        System.out.println("privateKey:" +a.get("privateKey"));
//        String sign = MakeSign("1234", a.get("privateKey"));
//        System.out.println("sign:" +sign);
//        System.out.println(VeriSign("123", sign, a.get("publicKey")));
//    }

    /**
     * 通过私钥对参数进行加密
     *
     * @param dataStr
     * @param privateKey
     * @return
     */
    public static String makeSign(String dataStr, String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        byte[] data = dataStr.getBytes();
        byte[] keyBytes = base64String2Byte(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);
        return new String(new Base64().encode(signature.sign()));
    }

    /**
     * 使用公钥
     *
     * @param dataOri
     * @param Singnature
     * @param publicKeyBase64Str
     * @return
     */
    public static boolean veriSign(String dataOri, String Singnature, String publicKeyBase64Str) {
        try {
            byte[] signed = base64String2Byte(Singnature);
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(base64String2Byte(publicKeyBase64Str));
            KeyFactory keyFactory = null;
            keyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = keyFactory.generatePublic(keySpec);
            //这个根据需求填充SHA1WithRSA或SHA256WithRSA
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
            signature.initVerify(publicKey);
            signature.update(dataOri.getBytes(StandardCharsets.UTF_8));
            return signature.verify(signed);
        } catch (Exception e) {
            log.error("veriSign exception.", e);
            return false;
        }
    }

    /**
     * base64字符串转字节数组
     *
     * @param base64Str
     * @return
     */
    public static byte[] base64String2Byte(String base64Str) {
        return Base64.decodeBase64(base64Str);
    }

    /**
     * 字节数组转base64字符串
     *
     * @param bytes
     * @return
     */
    public static String byte2Base64String(byte[] bytes) {
        return new String(new Base64().encode(bytes));
    }

}
